home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / streaming / qtstreamsplicer / qtstreamsplicer.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  23.4 KB  |  785 lines

  1. //////////
  2. //
  3. //    File:        QTStreamSplicer.c
  4. //
  5. //    Contains:    Code to splice a still frame onto a streamed movie.
  6. //
  7. //    Written by:    Dan Crow
  8. //    Revised by: Tim Monroe
  9. //
  10. //    Copyright:    © 1999 by Apple Computer, Inc., all rights reserved.
  11. //
  12. //    Change History (most recent first):
  13. //
  14. //       <4>         06/02/99    rtm        further work on QTSplicer_SpliceImageOverStream
  15. //       <3>         05/28/99    rtm        added QTSplicer_SpliceImageOverStream, for sound-only streams
  16. //       <2>         05/19/99    rtm        minor tweaking for Windows version; added some comments; added ability
  17. //                                    to save spliced file as self-contained
  18. //       <1>         05/18/99    rtm        first file from Dan Crow; modified to better cohere with QT SDK
  19. //                                    standards (did some renaming of variables and functions, but otherwise
  20. //                                    this is pretty much Dan's code)
  21. //
  22. //    This file defines two principal functions, QTSplicer_SpliceImageOntoStream and QTSplicer_SpliceImageOverStream.
  23. //    QTSplicer_SpliceImageOntoStream prompts the user for a picture and a streamed movie, which is assumed to have
  24. //    a video track. QTSplicer_SpliceImageOntoStream is designed to splice the selected picture onto the beginning of
  25. //    the streamed movie, so that that picture appears in place of the standard QuickTime pre-preroll sequence, for a
  26. //    user-specified duration.
  27. //
  28. //    QTSplicer_SpliceImageOverStream has a slightly different purpose. It prompts the user for a picture and a streamed
  29. //    movie, which is assumed to have no video track. QTSplicer_SpliceImageOverStream is designed to splice the picture
  30. //    over the streamed track for the entire duration of the streamed movie. You might want to do this to add a graphic
  31. //    to a streamed radio broadcast or to a streamed music selection.
  32. //
  33. //////////
  34.  
  35. #include "QTStreamSplicer.h"
  36.  
  37.  
  38. //////////
  39. //
  40. // QTSplicer_SpliceImageOntoStream
  41. //
  42. // Prompt the user for an image file and a streamed movie; then splice the image
  43. // onto the front of the stream, for a specific duration; save the new spliced movie.
  44. //
  45. // This function contains the user interface for getting the input image and movie,
  46. // the output spliced movie location, and the desired splicing settings. The function
  47. // QTSplicer_CreateSplicedOntoMovie does all the nitty-gritty movie creation stuff.
  48. //
  49. //////////
  50.  
  51. OSErr QTSplicer_SpliceImageOntoStream (void)
  52. {
  53.     FSSpec                myImageSpec;
  54.     FSSpec                myStreamSpec;
  55.     FSSpec                myMovieSpec;
  56.     Movie                myMovie = NULL;
  57.     Boolean                isScaleImage = false;
  58.     Boolean                isSelfContained = false;
  59.     Boolean                gotImage = false;
  60.     Boolean                gotStream = false;
  61.     short                myResID = movieInDataForkResID;
  62.     short                myRefNum = 0;
  63.     DialogPtr            myDialog = NULL;
  64.     DialogItemIndex        myItem = 0;
  65.     DialogItemType        myItemType;
  66.     Handle                myItemHandle = NULL;
  67.     Rect                myItemRect;
  68.     long                myImageDuration;
  69.     Str255                myDurationString;
  70.     OSErr                myErr = noErr;
  71.  
  72.     // prompt the user for the image file to splice onto the stream
  73.     do {
  74.         SFTypeList            myTypeList = {kQTFileTypeQuickTimeImage, 0, 0, 0};
  75.         StandardFileReply    myReply;
  76.         
  77.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  78.         if (myReply.sfGood) {
  79.             if (QTUtils_IsImageFile(&myReply.sfFile)) {
  80.                 myImageSpec = myReply.sfFile;
  81.                 gotImage = true;
  82.             }
  83.         } else {
  84.             break;        // if the user cancelled
  85.         }
  86.     } while (!gotImage);
  87.     
  88.     // prompt the user for the live stream file to splice onto the end of the created movie
  89.     do {
  90.         SFTypeList            myTypeList = {kQTFileTypeMovie, 0, 0, 0};
  91.         StandardFileReply    myReply;
  92.         
  93.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  94.         if (myReply.sfGood) {
  95.             if (QTSplicer_FileContainsStream(myReply.sfFile)) {
  96.                 myStreamSpec = myReply.sfFile;
  97.                 gotStream = true;
  98.             }
  99.         } else {
  100.             break;        // if the user cancelled
  101.         }
  102.     } while (!gotStream);
  103.     
  104.     // make sure we have both an image and a stream
  105.     if (!gotStream || !gotImage)
  106.         goto bail;
  107.  
  108.     // get the desired splicing settings; open up the Splicer dialog box
  109.     myDialog = GetNewDialog(kSpliceOntoDialogID, NULL, (WindowPtr)-1L);
  110.     if (myDialog == NULL)
  111.         goto bail;
  112.         
  113.     SetDialogDefaultItem(myDialog, kSpliceButtonDone);
  114.     MacShowWindow(myDialog);
  115.         
  116.     do {
  117.         ModalDialog(NULL, &myItem);
  118.         if ((myItem == kSpliceScaleCheckbox) || (myItem == kSelfContainedCheckbox)) {
  119.             Boolean            myValue;
  120.             
  121.             GetDialogItem(myDialog, myItem, &myItemType, &myItemHandle, &myItemRect);
  122.             myValue = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  123.             SetControlValue((ControlHandle)myItemHandle, !myValue);
  124.         }
  125.     } while (myItem != kSpliceButtonDone);
  126.     
  127.     // set the isScaleImage variable depending on the state of the kSpliceScaleCheckbox item
  128.     GetDialogItem(myDialog, kSpliceScaleCheckbox, &myItemType, &myItemHandle, &myItemRect);
  129.     isScaleImage = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  130.     
  131.     // set the isSelfContained variable depending on the state of the kSelfContainedCheckbox item
  132.     GetDialogItem(myDialog, kSelfContainedCheckbox, &myItemType, &myItemHandle, &myItemRect);
  133.     isSelfContained = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  134.     
  135.     // get the desired image duration from the kSpliceDuration item
  136.     GetDialogItem(myDialog, kSpliceDuration, &myItemType, &myItemHandle, &myItemRect);
  137.     GetDialogItemText(myItemHandle, myDurationString);
  138.     StringToNum(myDurationString, &myImageDuration);
  139.     
  140.     DisposeDialog(myDialog);
  141.  
  142.     // prompt the user for the location of the output spliced movie
  143.     {
  144.         StringPtr             myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveSplicePrompt);
  145.         StringPtr             myMovieFileName = QTUtils_ConvertCToPascalString(kSaveSpliceFileName);
  146.         StandardFileReply    myReply;
  147.  
  148.         StandardPutFile(myMoviePrompt, myMovieFileName, &myReply);
  149.         if (!myReply.sfGood)
  150.             goto bail;                // deal with user cancelling
  151.  
  152.         if (myReply.sfReplacing)
  153.             DeleteMovieFile(&myReply.sfFile);
  154.  
  155.         myMovieSpec = myReply.sfFile;
  156.  
  157.         free(myMoviePrompt);
  158.         free(myMovieFileName);
  159.  
  160.         // create a movie file for the destination ("spliced") movie
  161.         myErr = CreateMovieFile(&myMovieSpec, FOUR_CHAR_CODE('TVOD'), smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &myRefNum, &myMovie);
  162.         if (myErr != noErr)
  163.             goto bail;
  164.     }
  165.     
  166.     // now create a movie that contains the image file and the stream spliced together
  167.     myErr = QTSplicer_CreateSplicedOntoMovie(myImageSpec, myStreamSpec, myMovie, isScaleImage, isSelfContained, myImageDuration * kOneSecond);
  168.     if (myErr != noErr)
  169.         goto bail;
  170.         
  171.     // put the movie resource into the file
  172.     myErr = AddMovieResource(myMovie, myRefNum, &myResID, NULL);
  173.         
  174. bail:
  175.     if (myRefNum != 0)
  176.         CloseMovieFile(myRefNum);
  177.     
  178.     if (myMovie != NULL)
  179.         DisposeMovie(myMovie);
  180.     
  181.     return(myErr);
  182. }
  183.  
  184.  
  185. //////////
  186. //
  187. // QTSplicer_SpliceImageOverStream
  188. //
  189. // Prompt the user for an image file and a streamed movie, which is a sound-only stream;
  190. // then splice the image over the stream, for the duration of the stream; save the new spliced movie.
  191. //
  192. // This function contains the user interface for getting the input image and movie,
  193. // the output spliced movie location, and the desired splicing settings. The function
  194. // QTSplicer_CreateSplicedOverMovie does all the nitty-gritty movie creation stuff.
  195. //
  196. //////////
  197.  
  198. OSErr QTSplicer_SpliceImageOverStream (void)
  199. {
  200.     FSSpec                myImageSpec;
  201.     FSSpec                myStreamSpec;
  202.     FSSpec                myMovieSpec;
  203.     Movie                myMovie = NULL;
  204.     Boolean                isScaleImage = false;
  205.     Boolean                isSelfContained = false;
  206.     Boolean                gotImage = false;
  207.     Boolean                gotStream = false;
  208.     short                myResID = movieInDataForkResID;
  209.     short                myRefNum = 0;
  210.     DialogPtr            myDialog = NULL;
  211.     DialogItemIndex        myItem = 0;
  212.     DialogItemType        myItemType;
  213.     Handle                myItemHandle = NULL;
  214.     Rect                myItemRect;
  215.     long                myImageHeight;
  216.     long                myImageWidth;
  217.     Str255                myHeightString;
  218.     Str255                myWidthString;
  219.     OSErr                myErr = noErr;
  220.  
  221.     // prompt the user for the image file to splice over the stream
  222.     do {
  223.         SFTypeList            myTypeList = {kQTFileTypeQuickTimeImage, 0, 0, 0};
  224.         StandardFileReply    myReply;
  225.         
  226.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  227.         if (myReply.sfGood) {
  228.             if (QTUtils_IsImageFile(&myReply.sfFile)) {
  229.                 myImageSpec = myReply.sfFile;
  230.                 gotImage = true;
  231.             }
  232.         } else {
  233.             break;        // if the user cancelled
  234.         }
  235.     } while (!gotImage);
  236.     
  237.     // prompt the user for the live stream file to splice under the image file
  238.     do {
  239.         SFTypeList            myTypeList = {kQTFileTypeMovie, 0, 0, 0};
  240.         StandardFileReply    myReply;
  241.         
  242.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  243.         if (myReply.sfGood) {
  244.             if (QTSplicer_FileContainsStream(myReply.sfFile)) {
  245.                 myStreamSpec = myReply.sfFile;
  246.                 gotStream = true;
  247.             }
  248.         } else {
  249.             break;        // if the user cancelled
  250.         }
  251.     } while (!gotStream);
  252.     
  253.     // make sure we have both an image and a stream
  254.     if (!gotStream || !gotImage)
  255.         goto bail;
  256.  
  257.     // get the desired splicing settings; open up the Splicer dialog box
  258.     myDialog = GetNewDialog(kSpliceOverDialogID, NULL, (WindowPtr)-1L);
  259.     if (myDialog == NULL)
  260.         goto bail;
  261.         
  262.     SetDialogDefaultItem(myDialog, kSpliceButtonDone);
  263.     MacShowWindow(myDialog);
  264.         
  265.     do {
  266.         ModalDialog(NULL, &myItem);
  267.         if ((myItem == kSpliceScaleCheckbox) || (myItem == kSelfContainedCheckbox)) {
  268.             Boolean            myValue;
  269.             
  270.             GetDialogItem(myDialog, myItem, &myItemType, &myItemHandle, &myItemRect);
  271.             myValue = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  272.             SetControlValue((ControlHandle)myItemHandle, !myValue);
  273.         }
  274.     } while (myItem != kSpliceButtonDone);
  275.     
  276.     // set the isScaleImage variable depending on the state of the kSpliceScaleCheckbox item
  277.     GetDialogItem(myDialog, kSpliceScaleCheckbox, &myItemType, &myItemHandle, &myItemRect);
  278.     isScaleImage = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  279.     
  280.     // set the isSelfContained variable depending on the state of the kSelfContainedCheckbox item
  281.     GetDialogItem(myDialog, kSelfContainedCheckbox, &myItemType, &myItemHandle, &myItemRect);
  282.     isSelfContained = (Boolean)GetControlValue((ControlHandle)myItemHandle);
  283.     
  284.     if (isScaleImage) {
  285.         // get the desired image width from the kSpliceWidth item
  286.         GetDialogItem(myDialog, kSpliceWidth, &myItemType, &myItemHandle, &myItemRect);
  287.         GetDialogItemText(myItemHandle, myWidthString);
  288.         StringToNum(myWidthString, &myImageWidth);
  289.         
  290.         // get the desired image height from the kSpliceHeight item
  291.         GetDialogItem(myDialog, kSpliceHeight, &myItemType, &myItemHandle, &myItemRect);
  292.         GetDialogItemText(myItemHandle, myHeightString);
  293.         StringToNum(myHeightString, &myImageHeight);
  294.     }
  295.     
  296.     DisposeDialog(myDialog);
  297.  
  298.     // prompt the user for the location of the output spliced movie
  299.     {
  300.         StringPtr             myMoviePrompt = QTUtils_ConvertCToPascalString(kSaveSplicePrompt);
  301.         StringPtr             myMovieFileName = QTUtils_ConvertCToPascalString(kSaveSpliceFileName);
  302.         StandardFileReply    myReply;
  303.  
  304.         StandardPutFile(myMoviePrompt, myMovieFileName, &myReply);
  305.         if (!myReply.sfGood)
  306.             goto bail;                // deal with user cancelling
  307.  
  308.         if (myReply.sfReplacing)
  309.             DeleteMovieFile(&myReply.sfFile);
  310.  
  311.         myMovieSpec = myReply.sfFile;
  312.  
  313.         free(myMoviePrompt);
  314.         free(myMovieFileName);
  315.  
  316.         // create a movie file for the destination ("spliced") movie
  317.         myErr = CreateMovieFile(&myMovieSpec, FOUR_CHAR_CODE('TVOD'), smCurrentScript, createMovieFileDeleteCurFile | createMovieFileDontCreateResFile, &myRefNum, &myMovie);
  318.         if (myErr != noErr)
  319.             goto bail;
  320.     }
  321.     
  322.     // now create a movie that contains the image file and the stream spliced together
  323.     myErr = QTSplicer_CreateSplicedOverMovie(myImageSpec, myStreamSpec, myMovie, isScaleImage, isSelfContained, myImageHeight, myImageWidth);
  324.     if (myErr != noErr)
  325.         goto bail;
  326.         
  327.     // put the movie resource into the file
  328.     myErr = AddMovieResource(myMovie, myRefNum, &myResID, NULL);
  329.         
  330. bail:
  331.     if (myRefNum != 0)
  332.         CloseMovieFile(myRefNum);
  333.     
  334.     if (myMovie != NULL)
  335.         DisposeMovie(myMovie);
  336.     
  337.     return(myErr);
  338. }
  339.  
  340.  
  341. //////////
  342. //
  343. // QTSplicer_CreateSplicedOntoMovie
  344. //
  345. // Create a movie file that contains the specified movie, with the specified image
  346. // spliced onto the front for the specified duration.
  347. //
  348. //////////
  349.  
  350. OSErr QTSplicer_CreateSplicedOntoMovie (FSSpec theImageSpec, FSSpec theMovieSpec, Movie theSplicedMovie, Boolean isScaleImage, Boolean isSelfContained, long theImageDuration)
  351. {
  352.     short                        myRefNum = kInvalidFileRefNum;
  353.     short                        myResID = 0;
  354.     Movie                        myMovie = NULL;
  355.     MovieController                mySplicedController = NULL;
  356.     Rect                        myStreamBox, myImageRect;
  357.     GraphicsImportComponent        myImporter = NULL;
  358.     GWorldPtr                    myImageGWorld = NULL;
  359.     ComponentResult                myErr = noErr;
  360.                 
  361.     // open the streamed movie file
  362.     myErr = OpenMovieFile(&theMovieSpec, &myRefNum, fsRdPerm);
  363.     if (myErr != noErr)
  364.         goto bail;
  365.  
  366.     myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
  367.     if (myErr != noErr)
  368.         goto bail;
  369.     
  370.     // find out the size of the streamed movie
  371.     GetMovieBox(myMovie, &myStreamBox);
  372.     
  373.     // get a graphics importer for the image file
  374.     myErr = GetGraphicsImporterForFile(&theImageSpec, &myImporter);
  375.     if (myErr != noErr)
  376.         goto bail;
  377.                 
  378.     // get the size of the image
  379.     if (isScaleImage) {
  380.         myImageRect = myStreamBox;
  381.         MacOffsetRect(&myImageRect, -myStreamBox.left, -myStreamBox.top);
  382.     } else {
  383.         GraphicsImportGetBoundsRect(myImporter, &myImageRect);
  384.     }
  385.  
  386.     // allocate a new GWorld to draw the image into
  387.     myErr = QTNewGWorld(&myImageGWorld, 32, &myImageRect, NULL, NULL, kICMTempThenAppMemory);
  388.     if (myErr != noErr) {
  389.         if (myImporter != NULL)
  390.             CloseComponent(myImporter);
  391.         goto bail;
  392.     }
  393.     
  394.     // draw the picture into the GWorld
  395.     GraphicsImportSetGWorld(myImporter, myImageGWorld, NULL);
  396.     GraphicsImportSetBoundsRect(myImporter, &myImageRect);
  397.     GraphicsImportDraw(myImporter);
  398.     
  399.     // close the graphics importer component
  400.     if (myImporter != NULL)
  401.         CloseComponent(myImporter);
  402.     
  403.     // create a controller for the spliced movie
  404.     mySplicedController = NewMovieController(theSplicedMovie, &myStreamBox, 0);
  405.     
  406.     // make sure we can edit this movie
  407.     MCEnableEditing(mySplicedController, true);
  408.         
  409.     // paste the still image into the spliced movie as a new video track
  410.     myErr = QTSplicer_AddVideoTrackFromGWorld(&theSplicedMovie, myImageGWorld, myImageRect.right - myImageRect.left, myImageRect.bottom - myImageRect.top, theImageDuration);
  411.     if (myErr != noErr)
  412.         goto bail;
  413.  
  414.     // go to the end of the spliced movie; this jumps past the first track,
  415.     // which we have just pasted into the spliced movie.
  416.     QTSplicer_SetCurrentTime(mySplicedController, GetMovieDuration(theSplicedMovie));
  417.  
  418.     if (isSelfContained) {
  419.         Track            mySrcTrack = NULL;
  420.         Track            myDstTrack = NULL;
  421.         Media            myDstMedia = NULL;
  422.         Fixed            myWidth, myHeight;
  423.         
  424.         mySrcTrack = GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType);
  425.         if (mySrcTrack == NULL)
  426.             goto bail;
  427.         
  428.         GetTrackDimensions(mySrcTrack, &myWidth, &myHeight);
  429.         
  430.         myDstTrack = NewMovieTrack(theSplicedMovie, myWidth, myHeight, kNoVolume);
  431.         if (myDstTrack == NULL)
  432.             goto bail;
  433.         
  434.         myDstMedia = NewTrackMedia(myDstTrack, kQTSStreamMediaType, GetMovieTimeScale(theSplicedMovie), NULL, 0);
  435.         if (myDstTrack == NULL)
  436.             goto bail;
  437.         
  438.         myErr = BeginMediaEdits(myDstMedia);
  439.         if (myErr != noErr)
  440.             goto bail;
  441.         
  442.         myErr = CopyTrackSettings(mySrcTrack, myDstTrack);
  443.         if (myErr != noErr)
  444.             goto bail;
  445.         
  446.         myErr = InsertTrackSegment(mySrcTrack, myDstTrack, 0, (0x7FFFFFFF - GetMovieDuration(theSplicedMovie)), GetMovieDuration(theSplicedMovie));
  447.         if (myErr != noErr)
  448.             goto bail;
  449.         
  450.         myErr = EndMediaEdits(myDstMedia);
  451.         if (myErr != noErr)
  452.             goto bail;
  453.     } else {
  454.         // insert the streamed movie after the image track
  455.         myErr = InsertMovieSegment(myMovie, theSplicedMovie, 0, (0x7FFFFFFF - GetMovieDuration(theSplicedMovie)), GetMovieDuration(theSplicedMovie));
  456.         if (myErr != noErr)
  457.             goto bail;
  458.     }
  459.     
  460.     // select none on the resulting movie
  461.     QTSplicer_SetSelectionTimes(mySplicedController, 0, 0);
  462.     
  463.     // go to the start of the spliced movie
  464.     QTSplicer_SetCurrentTime(mySplicedController, 0);
  465.     
  466. bail:
  467.     if (myRefNum != 0)
  468.         CloseMovieFile(myRefNum);
  469.  
  470.     if (myImageGWorld != NULL) {
  471.         DisposeGWorld(myImageGWorld);
  472.         myImageGWorld = NULL;
  473.     }
  474.     
  475.     if (mySplicedController != NULL) {
  476.         DisposeMovieController(mySplicedController);
  477.     }
  478.     
  479.     return(myErr);
  480. }
  481.  
  482.  
  483. //////////
  484. //
  485. // QTSplicer_CreateSplicedOverMovie
  486. //
  487. // Create a movie file that contains the specified movie, with the specified image as the video track.
  488. //
  489. //////////
  490.  
  491. OSErr QTSplicer_CreateSplicedOverMovie (FSSpec theImageSpec, FSSpec theMovieSpec, Movie theSplicedMovie, Boolean isScaleImage, Boolean isSelfContained, long theImageHeight, long theImageWidth)
  492. {
  493.     short                        myRefNum = kInvalidFileRefNum;
  494.     short                        myResID = 0;
  495.     Movie                        myMovie = NULL;
  496.     MovieController                mySplicedController = NULL;
  497.     Rect                        myImageRect;
  498.     GraphicsImportComponent        myImporter = NULL;
  499.     GWorldPtr                    myImageGWorld = NULL;
  500.     Track                        mySrcTrack = NULL;
  501.     Track                        myDstTrack = NULL;
  502.     Media                        myDstMedia = NULL;
  503.     Fixed                        myWidth, myHeight;
  504.     ComponentResult                myErr = noErr;
  505.                 
  506.     // open the streamed movie file
  507.     myErr = OpenMovieFile(&theMovieSpec, &myRefNum, fsRdPerm);
  508.     if (myErr != noErr)
  509.         goto bail;
  510.  
  511.     myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
  512.     if (myErr != noErr)
  513.         goto bail;
  514.     
  515.     // get a graphics importer for the image file
  516.     myErr = GetGraphicsImporterForFile(&theImageSpec, &myImporter);
  517.     if (myErr != noErr)
  518.         goto bail;
  519.                 
  520.     // get the size of the image
  521.     if (isScaleImage) {
  522.         myImageRect.top = 0;
  523.         myImageRect.left = 0;
  524.         myImageRect.bottom = (short)theImageHeight;
  525.         myImageRect.right = (short)theImageWidth;
  526.     } else {
  527.         GraphicsImportGetBoundsRect(myImporter, &myImageRect);
  528.     }
  529.  
  530.     // allocate a new GWorld to draw the image into
  531.     myErr = QTNewGWorld(&myImageGWorld, 32, &myImageRect, NULL, NULL, kICMTempThenAppMemory);
  532.     if (myErr != noErr) {
  533.         if (myImporter != NULL)
  534.             CloseComponent(myImporter);
  535.         goto bail;
  536.     }
  537.     
  538.     // draw the picture into the GWorld
  539.     GraphicsImportSetGWorld(myImporter, myImageGWorld, NULL);
  540.     GraphicsImportSetBoundsRect(myImporter, &myImageRect);
  541.     GraphicsImportDraw(myImporter);
  542.     
  543.     // close the graphics importer component
  544.     if (myImporter != NULL)
  545.         CloseComponent(myImporter);
  546.     
  547.     // create a controller for the spliced movie
  548.     mySplicedController = NewMovieController(theSplicedMovie, &myImageRect, 0);
  549.     
  550.     // make sure we can edit this movie
  551.     MCEnableEditing(mySplicedController, true);
  552.         
  553.     // paste the still image into the spliced movie as a new video track
  554.     myErr = QTSplicer_AddVideoTrackFromGWorld(&theSplicedMovie, myImageGWorld, myImageRect.right - myImageRect.left, myImageRect.bottom - myImageRect.top, GetMovieDuration(myMovie));
  555.     if (myErr != noErr)
  556.         goto bail;
  557.             
  558.     //////////
  559.     //
  560.     // copy over the streamed track
  561.     //
  562.     //////////
  563.     
  564.     mySrcTrack = GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType);
  565.     if (mySrcTrack == NULL)
  566.         goto bail;
  567.     
  568.     GetTrackDimensions(mySrcTrack, &myWidth, &myHeight);
  569.     
  570.     myDstTrack = NewMovieTrack(theSplicedMovie, myWidth, myHeight, kNoVolume);
  571.     if (myDstTrack == NULL)
  572.         goto bail;
  573.     
  574.     myDstMedia = NewTrackMedia(myDstTrack, kQTSStreamMediaType, GetMovieTimeScale(theSplicedMovie), NULL, 0);
  575.     if (myDstTrack == NULL)
  576.         goto bail;
  577.     
  578.     if (isSelfContained)
  579.         BeginMediaEdits(myDstMedia);
  580.     
  581.     myErr = CopyTrackSettings(mySrcTrack, myDstTrack);
  582.     if (myErr != noErr)
  583.         goto bail;
  584.     
  585.     myErr = InsertTrackSegment(mySrcTrack, myDstTrack, 0, GetMovieDuration(myMovie), 0);
  586.     if (myErr != noErr)
  587.         goto bail;
  588.     
  589.     if (isSelfContained)
  590.         EndMediaEdits(myDstMedia);
  591.     
  592.     // select none on the resulting movie
  593.     QTSplicer_SetSelectionTimes(mySplicedController, 0, 0);
  594.     
  595.     // go to the start of the spliced movie
  596.     QTSplicer_SetCurrentTime(mySplicedController, 0);
  597.     
  598. bail:
  599.     if (myRefNum != 0)
  600.         CloseMovieFile(myRefNum);
  601.  
  602.     if (myImageGWorld != NULL) {
  603.         DisposeGWorld(myImageGWorld);
  604.         myImageGWorld = NULL;
  605.     }
  606.     
  607.     if (mySplicedController != NULL) {
  608.         DisposeMovieController(mySplicedController);
  609.     }
  610.     
  611.     return(myErr);
  612. }
  613.  
  614.  
  615. //////////
  616. //
  617. // QTSplicer_FileContainsStream
  618. //
  619. // Determine whether the specified movie file contains a streaming track.
  620. //
  621. // Returns true iff the file is a movie file that has at least one streaming
  622. // track in it, false otherwise.
  623. //
  624. //////////
  625.  
  626. Boolean QTSplicer_FileContainsStream (FSSpec theMovieFile)
  627. {
  628.     short        myRefNum = 0;
  629.     short        myResID = 0;
  630.     Movie        myMovie = NULL;
  631.     Boolean        myResult = false;
  632.     OSErr        myErr = noErr;
  633.  
  634.     myErr = OpenMovieFile(&theMovieFile, &myRefNum, fsRdPerm);
  635.     if (myErr != noErr)
  636.         goto bail;
  637.         
  638.     myErr = NewMovieFromFile(&myMovie, myRefNum, &myResID, NULL, newMovieActive, NULL);
  639.     if (myErr != noErr)
  640.         goto bail;
  641.     
  642.     if (GetMovieIndTrackType(myMovie, 1, kQTSStreamMediaType, movieTrackMediaType) != NULL)
  643.         myResult = true;
  644.     
  645. bail:
  646.     if (myRefNum != 0)
  647.         CloseMovieFile(myRefNum);
  648.  
  649.     return(myResult);
  650. }
  651.  
  652.  
  653. //////////
  654. //
  655. // QTSplicer_SetSelectionTimes
  656. //
  657. // Set the movie selection to the specified times.
  658. //
  659. //////////
  660.  
  661. OSErr QTSplicer_SetSelectionTimes (MovieController theController, TimeValue theTime1, TimeValue theTime2)
  662. {
  663.     TimeRecord             myTimeRecord;
  664.     Movie                myMovie = MCGetMovie(theController);
  665.     ComponentResult        myErr = noErr;
  666.     
  667.     myTimeRecord.value.hi = 0;
  668.     myTimeRecord.value.lo = theTime1;
  669.     myTimeRecord.base = 0;
  670.     myTimeRecord.scale = GetMovieTimeScale(myMovie);
  671.     myErr = MCDoAction(theController, mcActionSetSelectionBegin, &myTimeRecord);
  672.     if (myErr != noErr)
  673.         goto done;
  674.     
  675.     myTimeRecord.value.lo = theTime2 - theTime1;
  676.  
  677.     myErr = MCDoAction(theController, mcActionSetSelectionDuration, &myTimeRecord);
  678.     
  679. done:
  680.     return((OSErr)myErr);
  681. }
  682.  
  683.  
  684. //////////
  685. //
  686. // QTSplicer_SetCurrentTime
  687. //
  688. // Set the movie current time to the specified time.
  689. //
  690. //////////
  691.  
  692. OSErr QTSplicer_SetCurrentTime (MovieController theController, TimeValue theTime)
  693. {
  694.     TimeRecord             myTimeRecord;
  695.     Movie                myMovie = MCGetMovie(theController);
  696.     ComponentResult        myErr = noErr;
  697.     
  698.     myTimeRecord.value.hi = 0;
  699.     myTimeRecord.value.lo = theTime;
  700.     myTimeRecord.base = GetMovieTimeBase(myMovie);
  701.     myTimeRecord.scale = GetMovieTimeScale(myMovie);
  702.     myErr = MCDoAction(theController, mcActionGoToTime, &myTimeRecord);
  703.  
  704.     return((OSErr)myErr);
  705. }
  706.  
  707.  
  708. //////////
  709. //
  710. // QTSplicer_AddVideoTrackFromGWorld
  711. //
  712. // Add to the specified movie a video track, using the image in the specified GWorld.
  713. //
  714. //////////
  715.  
  716. OSErr QTSplicer_AddVideoTrackFromGWorld (Movie *theMovie, GWorldPtr theGW, short theWidth, short theHeight, long theImageDuration)
  717. {
  718.     Track                        myTrack = NULL;
  719.     Media                        myMedia = NULL;
  720.     ImageDescriptionHandle        myDesc = NULL;
  721.     Rect                        myRect;
  722.     long                        mySize;
  723.     Handle                        myData = NULL;
  724.     Ptr                            myDataPtr = NULL;
  725.     PixMapHandle                myDstPixMap = NULL;
  726.     OSErr                        myErr = noErr;
  727.     
  728.     // create a video track in the movie
  729.     myTrack = NewMovieTrack(*theMovie, FixRatio(theWidth, 1), FixRatio(theHeight, 1), kNoVolume);
  730.     myMedia = NewTrackMedia(myTrack, VideoMediaType, kOneSecond, NULL, 0);
  731.     
  732.     myRect.top = 0;
  733.     myRect.left = 0;
  734.     myRect.right = theWidth;
  735.     myRect.bottom = theHeight;
  736.     
  737.     // begin editing the new track
  738.     BeginMediaEdits(myMedia);
  739.  
  740.     // create a new image description; CompressImage will fill in the fields of this structure
  741.     myDesc = (ImageDescriptionHandle)NewHandle(4);
  742.     
  743.     myDstPixMap = GetGWorldPixMap(theGW);
  744.     LockPixels(myDstPixMap);
  745.     
  746.     myErr = GetMaxCompressionSize(myDstPixMap, &myRect, 0, codecNormalQuality, kAnimationCodecType, anyCodec, &mySize);
  747.     if (myErr != noErr)
  748.         goto bail;
  749.         
  750.     myData = NewHandle(mySize);
  751.     if (myData == NULL)
  752.         goto bail;
  753.         
  754.     HLockHi(myData);
  755.     myDataPtr = StripAddress(*myData);
  756.     
  757.     myErr = CompressImage(myDstPixMap, &myRect, codecNormalQuality, kAnimationCodecType, myDesc, myDataPtr);
  758.     if (myErr != noErr)
  759.         goto bail;
  760.         
  761.     myErr = AddMediaSample(myMedia, myData, 0, (**myDesc).dataSize, theImageDuration, (SampleDescriptionHandle)myDesc, 1, 0, NULL);
  762.     if (myErr != noErr)
  763.         goto bail;
  764.  
  765.     myErr = EndMediaEdits(myMedia);
  766.     if (myErr != noErr)
  767.         goto bail;
  768.  
  769.     myErr = InsertMediaIntoTrack(myTrack, 0, 0, GetMediaDuration(myMedia), fixed1);
  770.     
  771. bail:
  772.     if (myData != NULL) {
  773.         HUnlock(myData);
  774.         DisposeHandle(myData);
  775.     }
  776.  
  777.     if (myDesc != NULL)
  778.         DisposeHandle((Handle)myDesc);
  779.         
  780.     if (myDstPixMap != NULL)
  781.         UnlockPixels(myDstPixMap);
  782.     
  783.     return(myErr);
  784. }
  785.